#ifndef MIPS_H
#define MIPS_H

#include "../memmap.h"

#define R(i)   (cpu.r[i])
#define PC     (cpu.pc)

/* op: xxxx xxaa aaab bbbb cccc cddd ddxx xxxx */

#define _RS  ((op >> 21) & 0x1f) /* a */
#define _RT  ((op >> 16) & 0x1f) /* b */
#define _RD  ((op >> 11) & 0x1f) /* c */

#define _FS  ((op >> 11) & 0x1f) /* c */
#define _FT  ((op >> 16) & 0x1f) /* b */
#define _FD  ((op >>  6) & 0x1f) /* d */

#define _VR  ((op >>  0) & 0xff)
#define _CC ((op >> 18) & 0x07) /* 3 first of b */

#define _POS ((op >>  6) & 0x1f) /* d */
#define _SA  ((op >>  6) & 0x1f) /* d */
#define _END ((op >> 11) & 0x1f) /* c */

#define HI cpu.hi
#define LO cpu.lo

#define SOFFSET (s16)(op & 0xffff)
#define UOFFSET (u16)(op & 0xffff)
#define BRANCHADDR (SOFFSET << 2) + PC
#define MEMADDR (u32)(R(_RS) + SOFFSET)

enum
{
    ZR, /* 00 00 00000 */
    AT, /* 01 01 00001 */
    V0, /* 02 02 00010 */
    V1, /* 03 03 00011 */
    A0, /* 04 04 00100 */
    A1, /* 05 05 00101 */
    A2, /* 06 06 00110 */
    A3, /* 07 07 00111 */
    T0, /* 08 08 01000 */
    T1, /* 09 09 01001 */
    T2, /* 10 0A 01010 */
    T3, /* 11 0B 01011 */
    T4, /* 12 0C 01100 */
    T5, /* 13 0D 01101 */
    T6, /* 14 0E 01110 */
    T7, /* 15 0F 01111 */
    S0, /* 16 10 10000 */
    S1, /* 17 11 10001 */
    S2, /* 18 12 10010 */
    S3, /* 19 13 10011 */
    S4, /* 20 14 10100 */
    S5, /* 21 15 10101 */
    S6, /* 22 16 10110 */
    S7, /* 23 17 10111 */
    T8, /* 24 18 11000 */
    T9, /* 25 19 11001 */
    K0, /* 26 1a 11010 */
    K1, /* 27 1b 11011 */
    GP, /* 28 1c 11100 */
    SP, /* 29 1d 11101 */
    FP, /* 30 1e 11110 */
    RA  /* 31 1f 11111 */
};

enum
{
    VFPU_CTRL_PFXS,
    VFPU_CTRL_PFXT,
    VFPU_CTRL_PFXD,
    VFPU_CTRL_CC,
    VFPU_CTRL_INF4,
    VFPU_CTRL_RSV5,
    VFPU_CTRL_RSV6,
    VFPU_CTRL_REV,
    VFPU_CTRL_RCX0,
    VFPU_CTRL_RCX1,
    VFPU_CTRL_RCX2,
    VFPU_CTRL_RCX3,
    VFPU_CTRL_RCX4,
    VFPU_CTRL_RCX5,
    VFPU_CTRL_RCX6,
    VFPU_CTRL_RCX7
};

extern char *registers[32];
extern char *fregisters[32];
extern char *cop0streg[32];
extern char *cop0ctlreg[32];

typedef struct
{
    MemMap memMap;
    s32 r[32]; /* Registers */
    s32 cop0st[32]; /* Coprocessor 0 state registers */
    s32 cop0ctl[32]; /* Coprocessor 0 control registers */
    float f[32]; /* FPU registers */
    float v[128]; /* VFPU registers */
    s32 vfpuCtrl[15];

    u32 pc;
    s32 hi;
    s32 lo;

    s32 fcsr; /* fpu control register */
} CPUState;

void cpu_reset();

void cpu_writeFCR(s32 reg, s32 value);
s32 cpu_readFCR(s32 reg);
void cpu_setFcc(u8 value);
u8 cpu_getFcc();
u8 cpu_getRoundMode();

void cpu_showReg();

extern CPUState cpu;

#endif

